use model_graph_types::{
    connector::{Connector, ExecuteOptions, QueryOptions},
    database::{DataSource, DatabaseType},
    modeling::Value,
    transform::{DataTransformOptions, DataTransformUnit, DataTransformValuesUnit},
};

use sqlite_connector::SqliteConnector;

/// 根据数据库获取到元数据
pub async fn transform(
    source: &DataSource,
    target: &DataSource,
    unit: &DataTransformValuesUnit,
    options: &DataTransformOptions,
) -> anyhow::Result<()> {
    //连接数据库
    let source_connector = SqliteConnector::open(&source).await?;
    let target_connector = SqliteConnector::open(&target).await?;

    let table = &unit.table;
    let wheres = &unit.wheres;

    let ignore = options.ignore_errs;
    let ignore_id = options.ignore_id;

    let (query_sql, insert_sql) = _get_select_sql(&source_connector, table, ignore_id).await?;
    tracing::debug!("{}\n{}", query_sql, insert_sql);
    //
    let (_, result_values) = source_connector
        .query(
            &format!("{} {}", query_sql, wheres),
            &vec![Value::String(table.clone())],
            QueryOptions {},
        )
        .await?;

    for value in result_values {
        match value {
            Value::Array(cols) => {
                let result = target_connector
                    .execute(&insert_sql, &cols, ExecuteOptions::default())
                    .await;
                if !ignore {
                    if let Err(err) = result {
                        tracing::error!("transform:{}", err);
                        return Err(err);
                    }
                }
            }
            _ => {
                tracing::debug!("==");
            }
        }
    }
    Ok(())
}

async fn _get_select_sql(
    connector: &SqliteConnector,
    table: &String,
    ignore_id: bool,
) -> anyhow::Result<(String, String)> {
    //查询所有的列
    let query_sql = format!("PRAGMA table_info({})", table);
    //cid, name, type, notnull, dflt_value, pk
    let (_, result_values) = connector
        .query(&query_sql, &vec![], QueryOptions {})
        .await?;

    let mut column_names: Vec<String> = vec![];
    let mut args: Vec<String> = vec![];

    for value in result_values {
        match value {
            Value::Array(cols) => {
                if let Some(Value::String(col_name)) = cols.get(1) {
                    tracing::debug!("{}", col_name);
                    if ignore_id && col_name == "id" {
                        continue;
                    }
                    //
                    column_names.push(col_name.clone());
                    args.push(format!("${}", args.len() + 1));
                }
            }
            _ => {
                tracing::debug!("==");
            }
        }
    }

    let col_strs = column_names.join(",");
    let args_strs = args.join(",");

    Ok((
        format!("SELECT {} FROM {}", col_strs, table),
        format!("INSERT INTO {}({}) VALUES({})", table, col_strs, args_strs),
    ))
}
